package com.kds.smarthome.service.impl;

import com.kds.smarthome.entity.QuartzJob;
import com.kds.smarthome.mapper.QuartzJobMapper;
import com.kds.smarthome.quartz.SpringElJob;
import com.kds.smarthome.service.QuartzJobService;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

@Slf4j
@Service
@Transactional
public class QuartzJobServiceImpl implements QuartzJobService {

    @Autowired
    private Scheduler scheduler;

    @Autowired
    private QuartzJobMapper quartzJobMapper;

    @Override
    public List<QuartzJob> getAllJobs() {
        try {
            List<QuartzJob> jobList = new ArrayList<>();

            // 获取Quartz中所有的任务
            for (String groupName : scheduler.getJobGroupNames()) {
                for (JobKey jobKey : scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName))) {
                    QuartzJob job = getJobByKey(jobKey);
                    if (job != null) {
                        jobList.add(job);
                    }
                }
            }

            return jobList;
        } catch (SchedulerException e) {
            log.error("获取所有任务失败", e);
            throw new RuntimeException("获取任务列表失败", e);
        }
    }

    @Override
    public QuartzJob getJobById(String jobId) {
        return quartzJobMapper.selectById(jobId);
    }

    @Override
    public void addJob(QuartzJob job) {
        try {
            // 生成任务ID
            if (job.getJobId() == null || job.getJobId().trim().isEmpty()) {
                job.setJobId(UUID.randomUUID().toString().replace("-", ""));
            }

            // 设置默认值
            job.setCreateTime(new Date());
            job.setUpdateTime(new Date());
            job.setJobStatus("NORMAL");
            job.setExecuteCount(0);

            // 创建任务
            JobDetail jobDetail = JobBuilder.newJob(SpringElJob.class).withIdentity(job.getJobId(), job.getJobGroup()).withDescription(job.getDescription()).storeDurably().build();

            // 创建触发器
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
            CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(job.getJobId(), job.getJobGroup()).withSchedule(scheduleBuilder).build();

            // 计算下次执行时间
            job.setNextExecuteTime(trigger.getNextFireTime());

            // 保存任务到数据库
            quartzJobMapper.insert(job);

            // 调度任务
            scheduler.scheduleJob(jobDetail, trigger);

            // 如果任务是暂停状态
            if ("PAUSED".equals(job.getJobStatus())) {
                scheduler.pauseJob(JobKey.jobKey(job.getJobId(), job.getJobGroup()));
            }

        } catch (Exception e) {
            log.error("添加任务失败", e);
            throw new RuntimeException("添加任务失败", e);
        }
    }

    @Override
    public void updateJob(QuartzJob job) {
        try {
            QuartzJob existingJob = quartzJobMapper.selectById(job.getJobId());
            if (existingJob == null) {
                throw new RuntimeException("任务不存在，jobId: " + job.getJobId());
            }

            // 更新时间
            job.setUpdateTime(new Date());

            // 如果更新了CRON表达式，需要重新创建触发器
            if (job.getCronExpression() != null && !job.getCronExpression().equals(existingJob.getCronExpression())) {
                TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobId(), job.getJobGroup());

                // 创建新的CRON触发器
                CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
                CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();

                // 计算下次执行时间
                job.setNextExecuteTime(trigger.getNextFireTime());

                // 更新触发器
                scheduler.rescheduleJob(triggerKey, trigger);
            }

            // 更新任务到数据库
            quartzJobMapper.updateById(job);

        } catch (Exception e) {
            log.error("更新任务失败", e);
            throw new RuntimeException("更新任务失败", e);
        }
    }

    @Override
    public void removeAllJobs() {
        try {
            // 暂停所有Trigger（防止新任务触发）
            scheduler.pauseAll();

            // 遍历所有Job组并删除Job
            for (String groupName : scheduler.getJobGroupNames()) {
                for (JobKey jobKey : scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName))) {
                    scheduler.deleteJob(jobKey); // 删除Job及关联的Trigger
                }
            }

        } catch (SchedulerException e) {
            e.printStackTrace();
        } finally {
            try {
                scheduler.resumeAll(); // 恢复Trigger（此时已无任务）
            } catch (SchedulerException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void deleteJob(String jobId) {
        try {
            QuartzJob job = quartzJobMapper.selectById(jobId);
            if (job == null) {
                return;
            }

            // 从Quartz中删除任务
            JobKey jobKey = JobKey.jobKey(job.getJobId(), job.getJobGroup());
            scheduler.deleteJob(jobKey);

            // 从数据库中删除任务
            quartzJobMapper.deleteById(jobId);

        } catch (Exception e) {
            log.error("删除任务失败", e);
            throw new RuntimeException("删除任务失败", e);
        }
    }

    @Override
    public void pauseJob(String jobId) {
        try {
            QuartzJob job = quartzJobMapper.selectById(jobId);
            if (job == null) {
                throw new RuntimeException("任务不存在，jobId: " + jobId);
            }

            // 暂停任务
            JobKey jobKey = JobKey.jobKey(job.getJobId(), job.getJobGroup());
            scheduler.pauseJob(jobKey);

            // 更新任务状态
            job.setJobStatus("PAUSED");
            job.setUpdateTime(new Date());
            quartzJobMapper.updateById(job);

        } catch (Exception e) {
            log.error("暂停任务失败", e);
            throw new RuntimeException("暂停任务失败", e);
        }
    }

    @Override
    public void resumeJob(String jobId) {
        try {
            QuartzJob job = quartzJobMapper.selectById(jobId);
            if (job == null) {
                throw new RuntimeException("任务不存在，jobId: " + jobId);
            }

            // 恢复任务
            JobKey jobKey = JobKey.jobKey(job.getJobId(), job.getJobGroup());
            scheduler.resumeJob(jobKey);

            // 更新任务状态
            job.setJobStatus("NORMAL");
            job.setUpdateTime(new Date());
            quartzJobMapper.updateById(job);

        } catch (Exception e) {
            log.error("恢复任务失败", e);
            throw new RuntimeException("恢复任务失败", e);
        }
    }

    @Override
    public void runJobNow(String jobId) {
        try {
            QuartzJob job = quartzJobMapper.selectById(jobId);
            if (job == null) {
                throw new RuntimeException("任务不存在，jobId: " + jobId);
            }

            // 立即执行任务
            JobKey jobKey = JobKey.jobKey(job.getJobId(), job.getJobGroup());
            scheduler.triggerJob(jobKey);

        } catch (Exception e) {
            log.error("立即执行任务失败", e);
            throw new RuntimeException("立即执行任务失败", e);
        }
    }

    @Override
    public List<QuartzJob> getJobsByCondition(QuartzJob job) {
        return quartzJobMapper.selectByCondition(job);
    }

    @Override
    public List<QuartzJob> getRunningJobs() {
        try {
            List<QuartzJob> runningJobs = new ArrayList<>();

            // 获取执行器中正在执行的任务
            List<JobExecutionContext> executingJobs = scheduler.getCurrentlyExecutingJobs();
            for (JobExecutionContext context : executingJobs) {
                JobKey jobKey = context.getJobDetail().getKey();
                QuartzJob job = getJobByKey(jobKey);
                if (job != null) {
                    runningJobs.add(job);
                }
            }

            return runningJobs;
        } catch (SchedulerException e) {
            log.error("获取正在运行的任务失败", e);
            throw new RuntimeException("获取正在运行的任务失败", e);
        }
    }

    @Override
    public boolean checkCronExpression(String cronExpression) {
        try {
            CronScheduleBuilder.cronSchedule(cronExpression);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    @Override
    public List<String> getNextExecuteTimeList(String cronExpression, Integer count) {
        List<String> list = new ArrayList<>();
        if (count == null || count <= 0) {
            count = 5;
        }

        try {
            CronTrigger trigger = TriggerBuilder.newTrigger().withSchedule(CronScheduleBuilder.cronSchedule(cronExpression)).build();

            Date date = new Date();
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

            for (int i = 0; i < count; i++) {
                date = trigger.getFireTimeAfter(date);
                list.add(dateFormat.format(date));
            }
        } catch (Exception e) {
            log.error("获取CRON表达式的下次执行时间失败", e);
        }

        return list;
    }

    /**
     * 根据JobKey获取任务信息
     */
    private QuartzJob getJobByKey(JobKey jobKey) {
        try {
            // 从数据库获取任务
            String jobId = jobKey.getName();
            QuartzJob job = quartzJobMapper.selectById(jobId);

            if (job != null) {
                // 获取任务的触发器
                TriggerKey triggerKey = TriggerKey.triggerKey(jobId, job.getJobGroup());
                Trigger trigger = scheduler.getTrigger(triggerKey);

                // 设置下次执行时间
                if (trigger != null) {
                    job.setNextExecuteTime(trigger.getNextFireTime());
                }

                // 获取任务状态
                Trigger.TriggerState triggerState = scheduler.getTriggerState(triggerKey);
                job.setJobStatus(triggerState.name());
            }

            return job;
        } catch (Exception e) {
            log.error("获取任务详情失败", e);
            return null;
        }
    }
}
